#define  E_ADC
#include "H/ADC.H"

/*****************************************************
*函数名称：void ADC_Init(uchar R_VREF,uchar R_ADCCK)
*函数功能：ADC初始化
*入口参数：uchar R_VREF    ACD参考电压设置(取值0~3) 0：VDD为参考电压, 1：外部参考电压, 2：内部基准电压1.28V, 3：内部基准电压2.048V
           uchar R_ADCCK  ADC时钟分频设置,CLKPER=32M/4T（OSCD设置）
                          0：CLKPER,   1：CLKPER/2,   2：CLKPER/4, 
                          3：CLKPER/8, 4：CLKPER/16,  5：CLKPER/32,  
                          6：CLKPER/64,7：CLKPER/128
*出口参数：void
*****************************************************/
void ADC_Init(uchar R_VREF,uchar R_ADCCK)
{
    ADCON1=ADCCK(R_ADCCK)|ADCSPT(8);//ADC时钟|ADC采样时间8
//    ADC_OFFSET_ADJUST();//ADC失调校准,若想提高准确度此处调用该函数
    ADCON0=ADCVO_VREF_UNOUT|ADCCUR_0DOT5|ADCVREF(R_VREF);//不输出参考电压|模块电流0.5mA|ADC参考电压 
    ADCEN=1;                        //ADC使能
    delay_us(D_ADC_WAIT);           //延时120us,等待ADC模块稳定
//  ADCIE=1;                        //ADC中断使能
//  EA=1;                           //全局中断使能
}

/*****************************************************
*函数名称：uint ADC_SINGLE_PRO()
*函数功能：ADC单次采样
*入口参数：void
*出口参数：uint R_ADC_CODE  (单次结果)
*****************************************************/
uint ADC_SINGLE_PRO()
{     
    uint R_ADC_CODE=0;
    ADCS=1;
    while(!ADCE) {}
    ADCE=0;
    ADCS=0;
    R_ADC_CODE=((uint)(ADCOH&0X0F)<<8)+ADCOL;
    return R_ADC_CODE; 

}
/*****************************************************
*函数名称：uint ADC_AVERAGE_PRO()
*函数功能：单通道连续扫描10次，去掉最大最小值后取均值  
*入口参数：void
*出口参数：uint R_ADC_CODE  (平均值结果)
*****************************************************/
uint ADC_AVERAGE_PRO()
{        
    uchar i=0;
    uint  R_Code_Sum=0,R_ADC_CODE=0,R_Code_Min=0xFFFF,R_Code_Max=0;    
    for(i=0;i<10;i++)
    {
        ADCS=1;
        while(!ADCE) {}
        ADCE=0;
        ADCS=0;       //先关闭ADCS再存值做平均
        
        R_ADC_CODE=((uint)(ADCOH&0X0F)<<8)+ADCOL;

        if(R_ADC_CODE<R_Code_Min)
        {
            R_Code_Min=R_ADC_CODE;
        }
        if(R_ADC_CODE>R_Code_Max)
        {
            R_Code_Max=R_ADC_CODE;
        }
        R_Code_Sum+=R_ADC_CODE;
        if(i==9)
        {
            R_Code_Sum=R_Code_Sum-R_Code_Min-R_Code_Max;
            R_Code_Sum>>=3;
            R_ADC_CODE=R_Code_Sum;    
        }

    }
    return R_ADC_CODE; 
}
/*****************************************************
*函数名称：void ADC_CH(uchar R_CH) 
*函数功能：ADC通道选择
*入口参数：uchar R_CH： ADC通道选择   0~22：外部输入通道ADCx,  23：内部VDD/4,  24及其他：内部GND
*出口参数：void
*****************************************************/
void ADC_CH(uchar R_CH)
{
    ADCON3=R_CH;
    if(R_CH<=7)
    {
        ADCCFG0=1<<R_CH;
        ADCCFG1=0;
        ADCCFG2=0;
    }
    else if(7<R_CH<16)
    {
        R_CH-=8;
        ADCCFG1=1<<R_CH;
        ADCCFG2=0;
        ADCCFG0=0;
    }
    else if(15<R_CH<23)
    {
        R_CH-=16;
        ADCCFG2=1<<R_CH;
        ADCCFG1=0;
        ADCCFG0=0;
    }
    delay_us(D_ADC_WAIT);           //延时120us,等待ADC模块稳定
}
/*****************************************************
*函数名称：void ADC_OFFSET_ADJUST()
*函数功能：ADC失调校准,校准量对应ADCCODE从大到小为：0FH→00H（正向校准），再10H→1FH（负向校准）
*入口参数：void
*出口参数：void
*****************************************************/
void ADC_OFFSET_ADJUST()
{   
    uchar  R_ADCON2_BAK=0;//R_ADCON3=ADCON3,R_ADCON0=ADCON0;
    bit	   FLAG_FIND2_OK=0;

    ADCON3=ADCADDR_GND;	      //选择ADC 内部GND
    ADCON0=ADCVO_VREF_UNOUT|ADCCUR_0DOT5|ADCVREF_IN2048;//不输出参考电压,模块电流0.5mA,内2.048VREF		
    ADCON2=0x0F;
    ADCEN=1;                  //ADC使能
    delay_us(D_ADC_WAIT);     //延时120us,等待ADC模块稳定
    while(ADCON2!=0X1F)
    {        
        ADCS=1;
        while(!ADCE) {}
        ADCE=0;
        ADCS=0;               //先关闭ADCS再存值做平均
 
        if((ADCOH&0X0F)==0 )
        {
            if(ADCOL==1)break;           
            if(ADCOL==2)
            {
                R_ADCON2_BAK=ADCON2;
                FLAG_FIND2_OK=1;
            }
            if((ADCON2&0X10)==0)
            { 
               //正向校准
                if((ADCON2&0x0f)==0)
                {
                    ADCON2=ADCON2|0X10;
                }
                else
                {
                    ADCON2--;
                }
            }
            else
            {
                //负向校准
                if((ADCON2&0x0f)==0x1f)
                {
                    if(FLAG_FIND2_OK==1)
                    {
                        ADCON2=R_ADCON2_BAK;
                    }
                    break;
                }
                else
                {
                    ADCON2++;
                } 
            }
        }
    }
//    ADCON3=R_ADCON3;
//    ADCON0=R_ADCON0;
}











